package com.lai.laiojcodesandbox.manager;

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.Volume;
import com.github.dockerjava.core.DockerClientBuilder;
import com.lai.laiojcodesandbox.enums.LanguageEnums;
import com.lai.laiojcodesandbox.pool.DockerContainerPool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
 * 容器池 - 管理容器生命周期，创建和销毁容器
 */
@Component
@Slf4j
public class DockerContainerManager {

    /** dockerClient实例 */
    private final DockerClient dockerClient;

    /** 容器id集合 */
    private final List<String> containerIds = new ArrayList<>();

    /** 挂载目录（代码存放目录） */
    private static final String BIND_DIR = "/home/uu/桌面/laioj-codeSandbox/tmpCode";

    /** 容器池 */
    @Resource
    public DockerContainerPool dockerContainerPool;

    public DockerContainerManager() {
        this.dockerClient = DockerClientBuilder.getInstance().build();
    }

    @PostConstruct
    public void init() {
        // 获取镜像名称集合
        String[] images = LanguageEnums.getImagesByLanguage();
        int size = DockerContainerPool.QUEUE_SIZE;
        for (String image : images) {   // 遍历并逐个创建容器
            for (int i = 0; i < size; i++) {
                // 3.2 创建容器
                CreateContainerCmd containerCmd = dockerClient.createContainerCmd(image);
                HostConfig hostConfig = new HostConfig();
                // 设置内存
                hostConfig.withMemory(100 * 1024 * 1000L);
                // 设置内存交换（指文件写入硬盘
                hostConfig.withMemorySwap(0L);
                // 设置CPU数
                hostConfig.withCpuCount(1L);
                // 设置挂载目录
                String userDir = System.getProperty("user.dir");
                //String globalCodePathName = userDir + File.separator + BIND_DIR;
                hostConfig.withBinds(new Bind(BIND_DIR, new Volume("/app")));
                CreateContainerResponse createContainerResponse = containerCmd
                        .withHostConfig(hostConfig)
                        // 关闭网络配置
                        .withNetworkDisabled(true)
                        // 禁止根目录写入
                        .withReadonlyRootfs(true)
                        // 错误输出
                        .withAttachStderr(true)
                        // 标准输入
                        .withAttachStdin(true)
                        // 标准输出
                        .withAttachStdout(true)
                        // 创建交互终端
                        .withTty(true)
                        .exec();
                String containerId = createContainerResponse.getId();

                // 4. 启动容器
                dockerClient.startContainerCmd(containerId).exec();
                log.info("容器启动完成：{}",image + i);

                // 将容器Id放入集合中
                containerIds.add(containerId);
            }
        }

        // 初始化容器池队列
        dockerContainerPool.initializeContainers(containerIds);
        System.out.println("初始化后获取到的容器池："+dockerContainerPool.toString());
    }

    @PreDestroy
    public void destroyContainers() {
        // 销毁时清理容器
        while (true) {
            String containerId = dockerContainerPool.acquireContainer();
            if (containerId == null) break; // 如果没有容器了就退出循环
            try {
                dockerClient.stopContainerCmd(containerId).exec(); // 停止容器
                dockerClient.removeContainerCmd(containerId).withRemoveVolumes(true).exec(); // 删除容器
                log.info("成功销毁容器: {}",containerId);
            } catch (Exception e) {
                log.error("销毁容器时出错: {}", e.getMessage());
            }
        }
    }

    /**
     * 监测容器状态
     * 定时任务 - 五秒执行一次
     */
    @Scheduled(fixedRate = 5000)
    public void monitorContainer() {
        String[] containers = dockerContainerPool.toArray();
//        log.error("监测-容器组：{}", Arrays.toString(containers));
        for (String containerId : dockerContainerPool.toArray()) {
            try {
                InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(containerId).exec();
                String state = containerInfo.getState().getStatus();
//                log.error("监测-容器ID:{} - 状态:{}",containerId,state);

                // 处理容器状态，若异常则执行相应逻辑
                if (!"running".equals(state)) {
                    handleContainerIssue(containerId);
                }
            } catch (Exception e) {
                log.error("监测-监测容器出现异常：{}",e.getMessage());
            }
        }
    }

    /**
     * 容器故障恢复
     * @param containerId 容器id
     */
    public void handleContainerIssue(String containerId){
        log.error("容器状态异常,未在运行状态 - id：{}",containerId);
        try {
            dockerClient.startContainerCmd(containerId).exec();
            log.error("重启容器 - id：{}",containerId);
        } catch (Exception e) {
            log.error("重启容器失败 - id：{} - message：{}",containerId,e.getMessage());
        }
    }


}
